import threading

from flask import Flask, render_template, request, redirect, url_for, jsonify
import docker
import psutil  # 用于获取主机资源使用情况
import paho.mqtt.client as mqtt
import json

app = Flask(__name__)
client = docker.from_env()

#########################MQTT配置####################################
# MQTT配置
MQTT_BROKER = "192.168.6.235"
MQTT_PORT = 1883
MQTT_TOPIC_to_RES = "test_topic_from_sat"
MQTT_TOPIC_to_SEND = "test_topic_from_grd"

# MQTT客户端
mqtt_client = mqtt.Client(callback_api_version=mqtt.CallbackAPIVersion.VERSION2)

# 全局变量用于保存收到的消息
received_message = []
containers_info = ""

# MQTT收到消息的回调函数
def on_message(client, userdata, msg):
    global received_message
    global containers_info

    received_message=msg.payload.decode()
    print("MQTT received:", received_message)
    if "query!" in received_message:
        containers_info = received_message.split("!")[1]


# 连接MQTT代理并订阅主题
def connect_mqtt():
    mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)
    mqtt_client.subscribe(MQTT_TOPIC_to_RES)
    mqtt_client.on_message = on_message
    mqtt_client.loop_forever()

# 启动MQTT连接和Flask服务器
mqtt_thread = threading.Thread(target=connect_mqtt)
mqtt_thread.start()


####################################################################


def check_ports_availability(ports):
    used_ports = get_used_ports()
    for port in ports.values():
        if port in used_ports:
            return False
    return True


def adjust_ports(ports):
    new_ports = {}
    for container_port, host_port in ports.items():
        while host_port in get_used_ports():  # 检测端口是否被占用
            host_port += 1  # 自动调整端口
        new_ports[container_port] = host_port
    return new_ports


def get_used_ports():
    used_ports = set()
    containers = client.containers.list()
    for container in containers:
        ports = container.attrs['HostConfig']['PortBindings']
        if ports:
            for port_info in ports.values():
                if port_info:
                    used_ports.add(int(port_info[0]['HostPort']))
    return used_ports


def get_host_memory_usage():
    memory = psutil.virtual_memory()  # 获取内存使用情况
    return memory.percent


def check_host_memory_availability():
    host_memory_usage = get_host_memory_usage()
    if host_memory_usage > 60:
        return False
    else:
        return True


def create_container(image, container_name, ports, memory=None, cpu_percentage=None):
    try:

        # 检查端口是否可用，如果不可用则自动调整端口
        while not check_ports_availability(ports):
            ports = adjust_ports(ports)

        # 检查内存使用率是否超过60%
        if not check_host_memory_availability():
            print("提示：当前节点内存资源不足，停止创建")
            # 本地停止创建
            # 调度到隔壁节点尝试运行
            # 如果隔壁节点不能运行，则跑回本地，继续循环等待。。
            # 如果循环踢皮球x次，则停止调度，任务创建失败。

            return None

        # 将内存值从MB转换为B
        if memory is not None:
            memory = int(memory) * 1024 * 1024  # 将MB转换为B

        # 创建并启动容器
        container = client.containers.run(
            image,
            detach=True,
            tty=True,
            ports=ports,
            name=container_name,
            mem_limit=memory,  # 设置内存限制
            cpu_period=100000,  # 设置CPU周期
            cpu_quota=int(cpu_percentage * 10000),  # 设置CPU份额
        )
        print("容器创建并启动成功！")
        return container.id
    except docker.errors.APIError as e:
        print(f"出现错误：{e}")
        return None


# 获取容器列表
@app.route('/containers')
def list_containers():
    message = "query!"
    mqtt_client.publish(MQTT_TOPIC_to_SEND,message)
    global containers_info
    return jsonify(containers_info)



# 创建容器
@app.route('/containers/create', methods=['POST'])
def create_container_route():
    image = request.form.get('image', 'ubuntu')
    container_name = request.form.get('container_name', 'my_container')
    ports_str = request.form.get('ports', None)
    memory = request.form.get('memory', None)  # 获取内存值
    cpu_percentage = float(request.form.get('cpu_percentage', 50))  # 获取CPU使用率

    container_data = {
        'name': container_name,
        'cpu_cost': cpu_percentage,
        'memory_cost': memory,  # 将内存从B转换为MB
        'image': image,
        'ports': ports_str
    }

    message = "create!" + str(container_data)
    mqtt_client.publish(MQTT_TOPIC_to_SEND, message)

    return redirect(url_for('index'))


# 获取主机资源
@app.route('/host_resources')
def host_resources():
    memory = psutil.virtual_memory()

    return jsonify({
        'cpu_percent': psutil.cpu_percent(),
        'memory_percent': memory.percent,
        'memory_total': memory.total,
        'memory_used': memory.used
    })


# 启动容器
@app.route('/containers/<container_id>/start', methods=['POST'])
def start_container(container_id):
    container = client.containers.get(container_id)
    container.start()
    return '', 204


# 重启容器
@app.route('/containers/<container_id>/stop_and_restart', methods=['POST'])
def stop_and_restart_container(container_id):
    container = client.containers.get(container_id)
    container.restart()
    return '', 204


# 停止容器
@app.route('/containers/<container_id>/stop', methods=['POST'])
def stop_container(container_id):
    container = client.containers.get(container_id)
    container.stop()
    return '', 204


# 删除容器
@app.route('/containers/<container_id>/delete', methods=['POST'])
def delete_container(container_id):
    container = client.containers.get(container_id)
    container.remove(force=True)
    return '', 204


# 主页
@app.route('/')
def index():
    return render_template('index.html')


if __name__ == '__main__':
    app.run(debug=True)
